﻿using log4net;
using Microsoft.EntityFrameworkCore;
using Npgsql;
using PlaceOrder_Core.Helper;
using PlaceOrder_Core.Libraries.Postgresql;
using PlaceOrder_Core.Services.Interfaces;
using PlaceOrder_Shared.Models.Common;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static log4net.Appender.FileAppender;

namespace PlaceOrder_Core.Services.Instances
{
    public class Database : IDatabase
    {
        private IdbhostContext _writerContext;
        private readonly object _writeLocker = new object();
        private readonly object _readLocker = new object();
        private readonly object _closeLocker = new object();
        private int _outTime = 60;
        private int _readerNum = 0;
        private bool _isWriting = false;
        private bool _isReading = false;
        public IdbhostContext GetReaderContext()
        {
            lock (_readLocker)
            {
                _isReading = true;
                int duration = 0;
                while (_isWriting)
                {
                    Thread.Sleep(1000);
                    duration++;
                    if (duration >= _outTime)
                    {
                        break;
                    }
                }
                _writerContext?.Dispose();
                _readerNum++;
                var db = new IdbhostContext();
                var connection = db.Database.GetDbConnection();
                connection.StateChange += Connection_StateChange;
                return db;
            }
        }

        private void Connection_StateChange(object sender, System.Data.StateChangeEventArgs e)
        {
            if (e.CurrentState == System.Data.ConnectionState.Closed)
            {
                _readerNum--;
                _isReading = _readerNum > 0;
               
            }
            else if (e.CurrentState == System.Data.ConnectionState.Broken)
            {
                // 数据库连接异常时，重置 _readerNum 和 _isReading 变量
                AppLog.WriteInfo("当前读者数量为：" + _readerNum);
                AppLog.WriteInfo("数据库连接关闭了，处于Broken状态");
            }
        }

        public void CloseReader()
        {
        }

        public IdbhostContext GetWriterContext()
        {
            lock (_writeLocker)
            {
                int duration = 0;
                while (_isWriting || _isReading)
                {
                    Thread.Sleep(1000);
                    duration++;
                    if (duration >= _outTime)
                    {
                        break;
                    }
                }
                _isWriting = true;
                _writerContext = new IdbhostContext();
                return _writerContext;
            }
        }

        public void CloseWriter()
        {
            lock (_closeLocker)
            {
                _writerContext?.Dispose();
                _isWriting = false;
            }
        }

        private readonly ILog _log;
        public Database(ILog log)
        {
            _log = log;

            if (!File.Exists("base_config.ini"))
            {
                AppLog.WriteInfo("配置文件不存在");
                return;
            }
            if (BaseConfig == null)
            {
                try
                {
                    BaseConfig = new BaseConfigModel();
                    StreamReader sr = new StreamReader("base_config.ini");
                    BaseConfig.ConnectionString = sr.ReadLine() + $"ApplicationName = PlaceOrder_SERVER";
                    BaseConfig.HttpUrl = sr.ReadLine();
                    BaseConfig.WebSocketUrl = sr.ReadLine();
                    BaseConfig.LilyHttpUrl = sr.ReadLine();
                    sr.Close();

                    IdbhostContext.SqlStr = BaseConfig.ConnectionString;
                }
                catch (Exception ex)
                {
                    AppLog.WriteInfo("配置文件读取异常" + ex.Message);
                    return;
                }
            }
        }
        public static BaseConfigModel BaseConfig;
        public Database()
        {
        }
    }
}
